home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Floppyshop 2
/
Floppyshop - 2.zip
/
Floppyshop - 2.iso
/
art&graf.ix
/
art-3485
/
art-3871
/
mdl10
/
xdl.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-06-04
|
16KB
|
572 lines
/*
* xdl 2.0 -- display a DL animation in an X-window.
*
*
* Author:
* Jonas Yngvesson <jonas-y@isy.liu.se>
*
* Derived from dltogl.c by:
* George Phillips <phillips@cs.ubc.ca>
*
* Support for user defined animation speed:
* Per Beremark <per.beremark@telelogic.se>
*/
#include <stdio.h>
#include <signal.h>
#ifdef __convex__
#include <stdlib.h>
#else
#include <malloc.h>
#endif
#include <sys/types.h>
#include <sys/time.h>
#include <X11/Xos.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#define isneg16(x) ((x) & 0x8000)
#define neg16(x) ((~(x) + 1) & 0x7fff)
typedef struct {
int version;
int format;
int images_per_screen;
char title[21];
char author[21];
int num_screen;
int num_command;
} DL_info;
Display *x_display;
Window x_window;
int x_depth;
u_long pixels[256];
Pixmap *pixmap;
XImage *x_image;
GC gc_clear;
/*
* Initialize the colormap. I use a private one for PseudoColor,
* I was too tired to fiddle with allocating shared colors.
*/
static void
colormap_setup(fp, version)
FILE *fp;
int version;
{
Colormap cmap;
XColor color;
u_char pal[768];
int i;
/* Is this the border colour? */
if (version == 2)
for (i = 0; i < 3; i++)
fgetc(fp);
else
fgetc(fp);
/*
* Here comes the colormap.
*/
fread(pal, 1, 768, fp);
/*
* Set up for grayscale conversion on a monochrome display.
*/
if (x_depth == 1) {
for (i = 0; i < 256; i++) {
pixels[i] = (u_long)((pal[3 * i] << 2) * 0.30
+ (pal[3 * i + 1] << 2) * 0.59
+ (pal[3 * i + 2] << 2) * 0.11);
}
return;
}
/*
* Allocate colors on color displays.
*/
if (x_depth == 8) {
cmap = XCreateColormap(x_display, x_window,
DefaultVisual(x_display,
DefaultScreen(x_display)),
AllocNone);
} else {
cmap = DefaultColormap(x_display, DefaultScreen(x_display));
}
for (i = 0; i < 256; i++) {
/*
* X wants 16 bit color specs and VGA uses 6 ==> shift 10 bits.
*/
color.red = pal[3 * i ] << 10;
color.green = pal[3 * i + 1] << 10;
color.blue = pal[3 * i + 2] << 10;
XAllocColor(x_display, cmap, &color);
pixels[i] = color.pixel;
}
if (x_depth == 8) {
XSetWindowColormap(x_display, x_window, cmap);
}
}
/*
* Wait for a key to be pressed. In "dltogl" it was
* printed as a "waitkey" command to GL with a numeric
* argument. I don't know any GL commands so I don't know
* if the argument was a request to wait for a specific key
* or a timeout for how long to wait or anything else.
* I just wait forever for any key to be pressed.
*/
static void
wait_for_key()
{
XEvent event;
Bool done;
done = False;
while (!done) {
XNextEvent(x_display, &event);
if (event.type == KeyPress) {
done = True;
}
}
}
/*
* Set up the X window.
*/
static void
x_window_setup(title, author)
char *title;
char *author;
{
XSetWindowAttributes win_attr; /* storage for "window attributes" */
XSizeHints hints; /* storage for "window hints" */
XGCValues gcval;
int screen;
char label[256];
/*
* Open the display.
*/
if (NULL == (x_display = XOpenDisplay(NULL))) {
fputs("Can't open display.\n", stderr);
exit(1);
}
/*
* Create the window.
*/
screen = DefaultScreen(x_display);
x_depth = DefaultDepth(x_display, DefaultScreen(x_display));
x_window = XCreateSimpleWindow(x_display, DefaultRootWindow(x_display),
100, 100, 320, 200, 0,
BlackPixel(x_display, screen),
BlackPixel(x_display, screen));
/*
* set up "window hints" so that we won't be allowed to
* resize the window while it's running
*/
sprintf(label, "%s %s %s", title, (author[0] ? "by" : ""), author);
hints.flags = PSize | PMinSize | PMaxSize;
hints.width = hints.min_width = hints.max_width = 320;
hints.height = hints.min_height = hints.max_height = 200;
XSetStandardProperties(x_display, x_window, label, title,
None, NULL, 0, &hints);
/*
* Tell the server which events we want to recieve.
* Enable backing store so we don't have to worry
* about exposes (yes I know, backing store is not
* guaranteed, but it works for me, hah).
*/
win_attr.event_mask = KeyPressMask;
win_attr.backing_store = Always;
XChangeWindowAttributes(x_display, x_window,
CWEventMask | CWBackingStore, &win_attr);
gcval.foreground = BlackPixel(x_display, screen);
gc_clear = XCreateGC(x_display, x_window, GCForeground, &gcval);
XMapWindow(x_display, x_window);
XSync(x_display, False);
}
static void die(s)char*s;{fprintf(stderr,"%s\n",s);exit(1);}
void
main(argc, argv)
int argc;
char* argv[];
{
DL_info dlinfo;
struct itimerval timer;
struct timeval timeout;
char *filename;
FILE *fp;
u_char *image_data;
char *err1, *err2, *tmp;
short alpha[256], beta[256], gamma[256], delta[256];
short gray, err;
u_long black, white;
int dx, dy;
int width, height;
int *cmd;
int labelpos, label;
int cmdnum;
int frame_freq;
int fps = 25;
int zoomflag = 0;
int errflg = 0;
int i, j;
extern char *optarg;
extern int optind;
/*
* Lets see what option we got from the user.
*/
while ((i = getopt(argc, argv, "zhr:")) != -1) {
switch (i) {
case 'z':
zoomflag = 1;
break;
case 'h':
errflg++;
break;
case 'r':
fps = atoi(optarg);
if (fps < 2) {
printf("Minimum value is 2 frames per second.\n");
fps = 2;
}
break;
case '?':
default:
errflg++;
}
}
if (errflg) {
fputs("usage: xdl [-z] [-h] [-r frames/second] [file.dl]\n", stderr);
exit (2);
}
if (argv[optind] == NULL) {
fp = stdin;
filename = "stdin";
} else if (NULL == (fp = fopen(argv[optind], "r"))) {
fprintf(stderr, "xdl: can't open %s\n", argv[1]);
exit(1);
} else {
filename = argv[optind];
}
/*
* Check the version number...
*/
if (1 != (dlinfo.version = fgetc(fp)) && 2 != dlinfo.version) {
fprintf(stderr, "xdl: This file is in an unknown format.\n");
fprintf(stderr, " I can only do .DL version 1 and 2.\n",
dlinfo.version);
exit(1);
}
/*
* ...and the format.
*/
if (dlinfo.version == 1)
dlinfo.format = 1;
else
dlinfo.format = fgetc(fp);
switch (dlinfo.format) {
case 0: /* large */
dx = dy = 0;
width = 320;
height = 200;
dlinfo.images_per_screen = 1;
zoomflag = 0;
break;
case 1: /* medium */
if (zoomflag) {
dx = dy = 0;
width = 320;
height = 200;
} else {
dx = 80;
dy = 50;
width = 160;
height = 100;
}
dlinfo.images_per_screen = 4;
break;
default:
die("xdl: only large and medium formats are handled");
break;
}
/*
* Get title and author (if any).
*/
dlinfo.title[20] = dlinfo.author[20] = 0;
for (i = 0; i < 20; i++) {
dlinfo.title[i] = fgetc(fp) ^ 255;
if ((u_char)dlinfo.title[i] == 255) {
dlinfo.title[i] = 0;
}
}
for (i = 0; i < 20; i++) {
if (dlinfo.version == 2) {
dlinfo.author[i] = fgetc(fp) ^ 255;
if ((u_char)dlinfo.author[i] == 255) {
dlinfo.author[i] = 0;
}
} else {
dlinfo.author[i] = 0;
}
}
/*
* Read number of screens and commands.
*/
dlinfo.num_screen = fgetc(fp);
dlinfo.num_command = fgetc(fp);
/*
* Display what we know so far.
*/
printf("%s is a %s sized version %d .DL file.\n", filename,
(dlinfo.format == 0 ? "large" : "medium"),
dlinfo.version);
printf("It containes %d images in a %d frame loop.\n",
dlinfo.num_screen * dlinfo.images_per_screen, dlinfo.num_command);
if (dlinfo.format == 1 && zoomflag) {
puts("Zooming images to 320x200.");
}
printf("Displaying animation at %d frames per second.\n",fps);
/*
* Kick X into action.
*/
x_window_setup(dlinfo.title, dlinfo.author);
colormap_setup(fp, dlinfo.version);
/*
* Allocate memory for the commands, the image data
* and all the pixmaps.
*/
if (!(cmd = (int *)malloc(dlinfo.num_command * sizeof(int))))
die("xdl: out of memory");
if (NULL == (image_data = (u_char *)malloc(320 * 200))) {
die("xdl: not enough memory.");
}
if (NULL == (pixmap = (Pixmap *)malloc(dlinfo.num_screen
* dlinfo.images_per_screen
* sizeof(Pixmap)))) {
die("xdl: not enough memory.");
}
/*
* Set up for error distribution
* on monochrome displays.
*/
if (x_depth == 1) {
for (i = 0; i < 256; i++) {
alpha[i] = ((i - 128) * 7) / 16;
beta[i] = ((i - 128) * 3) / 16;
gamma[i] = ((i - 128) * 5) / 16;
delta[i] = ((i - 128) * 1) / 16;
}
err1 = malloc(322);
err2 = malloc(322);
black = BlackPixel(x_display, DefaultScreen(x_display));
white = WhitePixel(x_display, DefaultScreen(x_display));
}
/*
* Build the pixmaps for the animation.
*/
printf("Building pixmaps, wait..."); fflush(stdout);
for (j = 0; j < dlinfo.num_screen; j++) {
u_char *src;
int row;
int col;
/*
* Read one screen of data.
*/
fread(image_data, 1, 320 * 200, fp);
/*
* Each screen can hold several images.
*/
for (i = 0; i < dlinfo.images_per_screen; i++) {
if (x_depth == 1) {
bzero(err1, 322);
}
/*
* Get a pixmap for the image.
*/
pixmap[j * (dlinfo.format * 3 + 1) + i]
= XCreatePixmap(x_display, x_window, 320, 200, x_depth);
XFillRectangle(x_display, pixmap[j * (dlinfo.format * 3 + 1) + i],
gc_clear, 0, 0, 320, 200);
x_image = XGetImage(x_display,
pixmap[j * (dlinfo.format * 3 + 1) + i],
dx, dy, width, height, AllPlanes, ZPixmap);
/*
* Get a pointer to the beginning of this image.
* Put the pixels in the x-image and perform
* error distribution if needed. We do zooming
* by reading the same data several times, together
* with error distribution this gives us some smoothing
* for free! :-)
*/
src = image_data + (i % 2) * 160 + (i / 2) * 100 * 320;
for (row = 0; row < height; row++) {
if (x_depth == 1) {
bzero(err2, 322);
}
for (col = 0; col < width; col++) {
if (x_depth == 1) {
gray = pixels[*src] + err1[col + 1];
if (gray < 128) {
err = gray;
XPutPixel(x_image, col, row, black);
} else {
err = gray - 256;
XPutPixel(x_image, col, row, white);
}
err1[col + 2] += alpha[err + 128];
err2[col ] += beta[err + 128];
err2[col + 1] += gamma[err + 128];
err2[col + 2] += delta[err + 128];
} else {
XPutPixel(x_image, col, row, pixels[*src]);
}
src += (zoomflag) ? (col & 1) : 1;
}
if (x_depth == 1) {
tmp = err1;
err1 = err2;
err2 = tmp;
}
if (dlinfo.format) {
if (zoomflag) {
src += (row & 1) ? 160 : -160;
} else {
src += 160;
}
}
}
/*
* Put the image in the pixmap.
*/
XPutImage(x_display, pixmap[j * (dlinfo.format * 3 + 1) + i],
DefaultGC(x_display, DefaultScreen(x_display)),
x_image, 0, 0, dx, dy, width, height);
}
}
printf("done.\n");
/*
* Read the commands.
*/
for (i = 0; i < dlinfo.num_command; i++) {
if (dlinfo.version == 2) {
j = fgetc(fp);
j += fgetc(fp) << 8;
cmd[i] = j;
} else {
j = fgetc(fp);
cmd[i] = (j % 10) - 1 + ((j / 10) - 1) * 4;
}
}
labelpos = 0;
if (isneg16(cmd[dlinfo.num_command - 1])) {
labelpos = (neg16(cmd[dlinfo.num_command - 1])
+ 1); /* Correct? Why add 1 ?? */
dlinfo.num_command--; /* ignore that last command */
}
/*
* Now for the animation. I use setitimer() and getitimer()
* to try to keep 25 frames/sec. (Not that all DL-files are
* adjusted to that but it seem natural)
* However, as Per Beremark noted, most files seem to be tuned
* for 10 - 12 frames/sec so it is possible to change the
* speed with the -r switch.
*/
signal(SIGALRM, SIG_IGN);
frame_freq = 1000000/fps;
i = 0;
cmdnum = 0;
label = -1;
while (1) {
for (; i < dlinfo.num_command; i++, cmdnum++) {
if (cmdnum == labelpos && label == -1) {
label = i;
}
if (isneg16(cmd[i])) {
i++; /* Skip argument to waitkey, see above */
wait_for_key();
} else {
timer.it_interval.tv_sec = 0;
timer.it_interval.tv_usec = frame_freq;
timer.it_value.tv_sec = 0;
timer.it_value.tv_usec = frame_freq;
setitimer(ITIMER_REAL, &timer, NULL);
XCopyArea(x_display, pixmap[cmd[i]], x_window,
DefaultGC(x_display, DefaultScreen(x_display)),
0, 0, 320, 200, 0, 0);
XSync(x_display, False);
getitimer(ITIMER_REAL, &timer);
timeout = timer.it_value;
select(0, NULL, NULL, NULL, &timeout);
}
}
i = cmdnum = label;
}
}